#include "basechart_vector2d.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// BaseChartVector2D
////////////////////////////////////////////////////////////////////////////////////////////////////

/*! \class BaseChartVector2D
  \brief Represents two doubles as a mathematical 2D vector

  This class acts as a replacement for QVector2D with the advantage of double
  precision instead of single, and some convenience methods tailored for the
  QCustomPlot library.
*/

/* start documentation of inline functions */

/*! \fn void BaseChartVector2D::setX(double x)

  Sets the x coordinate of this vector to \a x.

  \see setY
*/

/*! \fn void BaseChartVector2D::setY(double y)

  Sets the y coordinate of this vector to \a y.

  \see setX
*/

/*! \fn double BaseChartVector2D::length() const

  Returns the length of this vector.

  \see lengthSquared
*/

/*! \fn double BaseChartVector2D::lengthSquared() const

  Returns the squared length of this vector. In some situations, e.g. when just
  trying to find the shortest vector of a group, this is faster than calculating
  \ref length, because it avoids calculation of a square root.

  \see length
*/

/*! \fn double BaseChartVector2D::angle() const

  Returns the angle of the vector in radians. The angle is measured between the
  positive x line and the vector, counter-clockwise in a mathematical coordinate
  system (y axis upwards positive). In screen/widget coordinates where the y
  axis is inverted, the angle appears clockwise.
*/

/*! \fn QPoint BaseChartVector2D::toPoint() const

  Returns a QPoint which has the x and y coordinates of this vector, truncating
  any floating point information.

  \see toPointF
*/

/*! \fn QPointF BaseChartVector2D::toPointF() const

  Returns a QPointF which has the x and y coordinates of this vector.

  \see toPoint
*/

/*! \fn bool BaseChartVector2D::isNull() const

  Returns whether this vector is null. A vector is null if \c qIsNull returns
  true for both x and y coordinates, i.e. if both are binary equal to 0.
*/

/*! \fn BaseChartVector2D BaseChartVector2D::perpendicular() const

  Returns a vector perpendicular to this vector, with the same length.
*/

/*! \fn double BaseChartVector2D::dot() const

  Returns the dot/scalar product of this vector with the specified vector \a
  vec.
*/

/* end documentation of inline functions */

/*!
  Creates a BaseChartVector2D object and initializes the x and y coordinates to
  0.
*/
BaseChartVector2D::BaseChartVector2D() : mX(0), mY(0) {}

/*!
  Creates a BaseChartVector2D object and initializes the \a x and \a y
  coordinates with the specified values.
*/
BaseChartVector2D::BaseChartVector2D(double x, double y) : mX(x), mY(y) {}

/*!
  Creates a BaseChartVector2D object and initializes the x and y coordinates
  respective coordinates of the specified \a point.
*/
BaseChartVector2D::BaseChartVector2D(const QPoint& point)
    : mX(point.x()), mY(point.y()) {}

/*!
  Creates a BaseChartVector2D object and initializes the x and y coordinates
  respective coordinates of the specified \a point.
*/
BaseChartVector2D::BaseChartVector2D(const QPointF& point)
    : mX(point.x()), mY(point.y()) {}

/*!
  Normalizes this vector. After this operation, the length of the vector is
  equal to 1.

  If the vector has both entries set to zero, this method does nothing.

  \see normalized, length, lengthSquared
*/
void BaseChartVector2D::normalize() {
  if (mX == 0.0 && mY == 0.0) return;
  const double lenInv = 1.0 / length();
  mX *= lenInv;
  mY *= lenInv;
}

/*!
  Returns a normalized version of this vector. The length of the returned vector
  is equal to 1.

  If the vector has both entries set to zero, this method returns the vector
  unmodified.

  \see normalize, length, lengthSquared
*/
BaseChartVector2D BaseChartVector2D::normalized() const {
  if (mX == 0.0 && mY == 0.0) return *this;
  const double lenInv = 1.0 / length();
  return BaseChartVector2D(mX * lenInv, mY * lenInv);
}

/*! \overload

  Returns the squared shortest distance of this vector (interpreted as a point)
  to the finite line segment given by \a start and \a end.

  \see distanceToStraightLine
*/
double BaseChartVector2D::distanceSquaredToLine(
    const BaseChartVector2D& start, const BaseChartVector2D& end) const {
  const BaseChartVector2D v(end - start);
  const double vLengthSqr = v.lengthSquared();
  if (!qFuzzyIsNull(vLengthSqr)) {
    const double mu = v.dot(*this - start) / vLengthSqr;
    if (mu < 0)
      return (*this - start).lengthSquared();
    else if (mu > 1)
      return (*this - end).lengthSquared();
    else
      return ((start + mu * v) - *this).lengthSquared();
  } else
    return (*this - start).lengthSquared();
}

/*! \overload

  Returns the squared shortest distance of this vector (interpreted as a point)
  to the finite line segment given by \a line.

  \see distanceToStraightLine
*/
double BaseChartVector2D::distanceSquaredToLine(const QLineF& line) const {
  return distanceSquaredToLine(BaseChartVector2D(line.p1()),
                               BaseChartVector2D(line.p2()));
}

/*!
  Returns the shortest distance of this vector (interpreted as a point) to the
  infinite straight line given by a \a base point and a \a direction vector.

  \see distanceSquaredToLine
*/
double BaseChartVector2D::distanceToStraightLine(
    const BaseChartVector2D& base, const BaseChartVector2D& direction) const {
  return qAbs((*this - base).dot(direction.perpendicular())) /
         direction.length();
}

/*!
  Scales this vector by the given \a factor, i.e. the x and y components are
  multiplied by \a factor.
*/
BaseChartVector2D& BaseChartVector2D::operator*=(double factor) {
  mX *= factor;
  mY *= factor;
  return *this;
}

/*!
  Scales this vector by the given \a divisor, i.e. the x and y components are
  divided by \a divisor.
*/
BaseChartVector2D& BaseChartVector2D::operator/=(double divisor) {
  mX /= divisor;
  mY /= divisor;
  return *this;
}

/*!
  Adds the given \a vector to this vector component-wise.
*/
BaseChartVector2D& BaseChartVector2D::operator+=(
    const BaseChartVector2D& vector) {
  mX += vector.mX;
  mY += vector.mY;
  return *this;
}

/*!
  subtracts the given \a vector from this vector component-wise.
*/
BaseChartVector2D& BaseChartVector2D::operator-=(
    const BaseChartVector2D& vector) {
  mX -= vector.mX;
  mY -= vector.mY;
  return *this;
}